using System;
using System.Collections.Generic;
using System.Text;

namespace AIFSCMSClient
{
    /// <summary>
    /// Fact Expression Builder will be used by Clients that just need to build their facts and check against
    /// existing rules in the repository.
    /// This should not be used by Rule building application because of it's limitted operator exposure. This class
    /// only supports equal to and is null operators.
    /// RuleExpressionBuilder should be used for rule building.
    /// </summary>
    /// <see cref="RuleExpressionBuilder"/>
    /// <example>
    ///  <code>
    ///     FactExpressionBuilder builder = new FactExpressionBuilder();
    ///     string[] expressions = builder.Createbuilder.CreateStringCriteria("COUNTRY").IsEqualTo("US")
    ///            .AndNumericCriteria("POLICY_YEAR").IsEqualTo("2011").CriteriaExpression;
    ///     //Once a call to CriteriaExpression is called the buffer is cleared for new expression building
    ///  </code>
    /// </example>
    public class FactExpressionBuilder
    {
        public class CriteriaBuilderResult
        {
            Queue<string> buffer;
            internal CriteriaBuilderResult(Queue<string> Buffer)
            {
                buffer = Buffer;
            }

            /// <summary>
            /// Gets the current expression array. Once you call this method the buffer is cleared and
            /// the builder is ready for new expression building
            /// </summary>
            public string[] CriteriaExpression
            {
                get
                {
                    string[] buff = buffer.ToArray();

                    buffer.Clear();

                    return buff;
                }
            }

            /// <summary>
            /// Used internally to queue the criteria and operators
            /// </summary>
            internal Queue<string> CriteriaExpressionQueue
            {
                get
                {
                    return buffer;
                }
            }

            private CriteriaPredicate AndCriteria(string CriteriaName, string DataType)
            {
                FactExpressionBuilder builder = new FactExpressionBuilder(buffer);
                return builder.CreateCriteria(CriteriaName, DataType);
            }

            public CriteriaPredicate AndStringCriteria(string CriteriaName)
            {
                FactExpressionBuilder builder = new FactExpressionBuilder(buffer);
                return builder.CreateCriteria(CriteriaName, "STRING");
            }

            public CriteriaPredicate AndDateCriteria(string CriteriaName)
            {
                FactExpressionBuilder builder = new FactExpressionBuilder(buffer);
                return builder.CreateCriteria(CriteriaName, "DATE");
            }

            public CriteriaPredicate AndBooleanCriteria(string CriteriaName)
            {
                FactExpressionBuilder builder = new FactExpressionBuilder(buffer);
                return builder.CreateCriteria(CriteriaName, "BOOLEAN");
            }

            public CriteriaPredicate AndNumericCriteria(string CriteriaName)
            {
                FactExpressionBuilder builder = new FactExpressionBuilder(buffer);
                return builder.CreateCriteria(CriteriaName, "NUMERIC");
            }
        }

        public class CriteriaPredicate
        {
            Queue<string> buffer;

            internal CriteriaPredicate(Queue<string> Buffer)
            {
                buffer = Buffer;
            }

            public CriteriaBuilderResult IsEqualTo(string value)
            {
                buffer.Enqueue("=");
                buffer.Enqueue(value);

                CriteriaBuilderResult result = new CriteriaBuilderResult(buffer);
                return result;
            }            

            public CriteriaBuilderResult IsNull()
            {
                buffer.Enqueue("=");
                buffer.Enqueue("NULL");

                CriteriaBuilderResult result = new CriteriaBuilderResult(buffer);
                return result;
            }
        }

        Queue<string> buffer;

        public FactExpressionBuilder()
        {
            buffer = new Queue<string>();
        }

        internal FactExpressionBuilder(Queue<string> Buffer)
        {
            buffer = Buffer;
        }

        private CriteriaPredicate CreateCriteria(string CriteriaName, string DataType)
        {
            if (string.IsNullOrEmpty(CriteriaName))
                throw new ArgumentNullException("CriteriaName");

            buffer.Enqueue(CriteriaName);
            buffer.Enqueue(DataType);

            CriteriaPredicate criteriaOperator = new CriteriaPredicate(buffer);
            return criteriaOperator;
        }

        public CriteriaPredicate CreateStringCriteria(string CriteriaName)
        {
            return CreateCriteria(CriteriaName, "STRING");
        }

        public CriteriaPredicate CreateDateCriteria(string CriteriaName)
        {
            return CreateCriteria(CriteriaName, "DATE");
        }

        public CriteriaPredicate CreateBooleanCriteria(string CriteriaName)
        {
            return CreateCriteria(CriteriaName, "BOOLEAN");
        }

        public CriteriaPredicate CreateNumericCriteria(string CriteriaName)
        {
            return CreateCriteria(CriteriaName, "NUMERIC");
        }
    }
}
